package org.roulette.core;

import org.roulette.exception.NoMoreDataException;
import org.roulette.generator.DefaultNumberGenerator;
import org.roulette.generator.NumberGenerator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.roulette.utils.RouletteType;

/**
 *
 * @author hudimar
 */
public class Wheel {
	private List<Integer> history = new ArrayList<Integer>();
	private NumberGenerator numberGenerator = null;

	private Collection<WheelListener> listeners = new ArrayList<WheelListener>();
	private Collection<OneRoundListener> oneRoundListeners = new ArrayList<OneRoundListener>();

	private RouletteType type = null;
	private boolean gameEnd = false;

	public Wheel(){
		type = RouletteType.american;
		numberGenerator = new DefaultNumberGenerator();
		numberGenerator.setRange(type.getRangeStart(), type.getRangeEnd());
	}

	public Wheel(NumberGenerator numberGenerator, RouletteType type){
		this.type = type;
		this.numberGenerator = numberGenerator;
		numberGenerator.setRange(type.getRangeStart(), type.getRangeEnd());
	}

	public void addListener(WheelListener listener){
		listeners.add(listener);
	}

	public void removeListener(WheelListener listener){
		listeners.remove(listener);
	}

	public void removeAllListeners(){
		listeners.clear();
	}

	public List<Integer> getHistory(){
		return Collections.unmodifiableList(history);
	}

	public void rotate(){
		if(isGameEnd()){
			return;
		}
		else if(isNextRoundPossible()){
			try {
				int number = getNumer();
				history.add(number);
				for (OneRoundListener listener : oneRoundListeners) {
					listener.passResult(number);
				}
				oneRoundListeners.clear();
			} catch (NoMoreDataException ex) {
				ex.printStackTrace();
				gameEnd();
			}
		}else{
			gameEnd();
		}
	}

	public void placeBets(){
		if(isGameEnd()){
			return;
		}
		else if(isNextRoundPossible()){
			for(WheelListener better: listeners){
				Bet bet = better.placeNextBet(type);
				if(isBetValid(bet))
					oneRoundListeners.add(bet);
			}
		}else{
			gameEnd();
		}
	}

	public boolean isBetValid(Bet bet){
		//TODO set wheel rules as max bet, max possible win, ...
		//TODO check bet validness
		//bet.setInvalid("message");
		return true;
	}

	private boolean isNextRoundPossible(){
		return numberGenerator.isNextNumber();
	}

	public void gameEnd(){
		gameEnd = true;
		for(WheelListener better: listeners){
			better.gameEnd();
		}
	}

	public boolean isGameEnd(){
		return gameEnd;
	}

	private int getNumer() throws NoMoreDataException{
		//TODO test: numberGenerator.isNextNumber();
		return numberGenerator.generateNumber();
	}

	public void setNumberGenerator(NumberGenerator generator){
		this.numberGenerator = generator;
		numberGenerator.setRange(type.getRangeStart(), type.getRangeEnd());
	}
}
